<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="CypiW" id="CypiW"><span data-lake-id="u022048d4" id="u022048d4">典型回答</span></h1>
  <p data-lake-id="ubc06bb29" id="ubc06bb29"><br></p>
  <p data-lake-id="u8986517a" id="u8986517a"><span data-lake-id="u2e0c031f" id="u2e0c031f">缓存击穿：是指当某一key的缓存过期时大并发量的请求同时访问此key，瞬间击穿缓存服务器直接访问数据库，让数据库处于负载的情况。</span></p>
  <p data-lake-id="u8ca26acc" id="u8ca26acc"><span data-lake-id="ucb10549e" id="ucb10549e">​</span><br></p>
  <p data-lake-id="u54ec900a" id="u54ec900a"><span data-lake-id="u4add7f98" id="u4add7f98">缓存穿透：是指缓存服务器中没有缓存数据，数据库中也没有符合条件的数据，导致业务系统每次都绕过缓存服务器查询下游的数据库，缓存服务器完全失去了其应用的作用。</span></p>
  <p data-lake-id="u17ab7c37" id="u17ab7c37"><span data-lake-id="u39fde875" id="u39fde875">​</span><br></p>
  <p data-lake-id="u60b59292" id="u60b59292"><span data-lake-id="u158f99b3" id="u158f99b3">缓存雪崩：是指当大量缓存同时过期或缓存服务宕机，所有请求的都直接访问数据库，造成数据库高负载，影响性能，甚至数据库宕机。</span></p>
  <p data-lake-id="ude598b85" id="ude598b85"><span data-lake-id="u701ab935" id="u701ab935">​</span><br></p>
  <p data-lake-id="u20711c20" id="u20711c20"><span data-lake-id="u0c511850" id="u0c511850">在记忆这几个概念的时候，不要死记硬背，你可以尝试这样记忆：</span></p>
  <p data-lake-id="u2a7e50f0" id="u2a7e50f0"><span data-lake-id="u631310fc" id="u631310fc">​</span><br></p>
  <p data-lake-id="ue04866c6" id="ue04866c6"><span data-lake-id="ue5aecc2b" id="ue5aecc2b">首先，雪崩的概念比较容易记，就是很多个Key同时过期才会雪崩，"缓存雪崩的时候没有一个Key是无辜的"。至于穿透和击穿，区别在于穿透是"透"，什么叫透呢，那就是不仅缓存被击穿了，数据库也被击穿了，这种才叫透。所以，这种缓存和数据库中都没有的情况叫做"缓存穿透"。</span></p>
  <p data-lake-id="u2efd40a4" id="u2efd40a4"><br></p>
  <h1 data-lake-id="kHnGc" id="kHnGc"><span data-lake-id="ud709cc0c" id="ud709cc0c">扩展知识</span></h1>
  <h2 data-lake-id="tDSf3" id="tDSf3"><span data-lake-id="u1cd96b3e" id="u1cd96b3e">缓存穿透</span></h2>
  <p data-lake-id="ubdd87624" id="ubdd87624"><br></p>
  <p data-lake-id="u8d572e56" id="u8d572e56"><span data-lake-id="u882feaed" id="u882feaed">举个例子，一个女孩子去门店买口红，到了门店之后被告知她想要的那个色号已经没有了。于是她要求店员去问总部还有没有货。总部发现这个色号也没有了，于是女孩子就离开了。</span></p>
  <p data-lake-id="ud064db58" id="ud064db58"><br></p>
  <p data-lake-id="u5a6d01f9" id="u5a6d01f9"><span data-lake-id="u3f350205" id="u3f350205">过了一会另一个女孩子又来了，也想要购买同一个色号，店员就又总部问了一次。如此反复。</span></p>
  <p data-lake-id="u28eb7f0a" id="u28eb7f0a"><br></p>
  <p data-lake-id="u0575b448" id="u0575b448"><span data-lake-id="ub3348e25" id="ub3348e25">女孩子买口红不仅需要门店帮忙查询，还需要总部也进行盘货。类似这种情况，在缓存领域有一个类似的概念叫做</span><strong><span data-lake-id="u764cfd2f" id="u764cfd2f">缓存穿透</span></strong><span data-lake-id="uc5bf0be4" id="uc5bf0be4">。</span></p>
  <p data-lake-id="ud343cbc8" id="ud343cbc8"><br></p>
  <p data-lake-id="ud140a83d" id="ud140a83d"><img src="http://www.hollischuang.com/wp-content/uploads/2020/12/16089699210638.jpg?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_29%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"><span data-lake-id="udabc2693" id="udabc2693">​</span></p>
  <p data-lake-id="u16f3d560" id="u16f3d560"><br></p>
  <p data-lake-id="u06260a20" id="u06260a20"><span data-lake-id="ufdea4a14" id="ufdea4a14">缓存穿透是指缓存服务器中没有缓存数据，数据库中也没有符合条件的数据，导致业务系统每次都绕过缓存服务器查询下游的数据库，缓存服务器完全失去了其应用的作用。</span></p>
  <p data-lake-id="u2fcaa833" id="u2fcaa833"><br></p>
  <h3 data-lake-id="bZba7" id="bZba7"><span data-lake-id="ue06bf696" id="ue06bf696">缓存空值</span></h3>
  <p data-lake-id="u711f329f" id="u711f329f"><br></p>
  <p data-lake-id="u85b59bd8" id="u85b59bd8"><span data-lake-id="uabb1b348" id="uabb1b348">解决多次询问总部的方法比较简单，如果口红门店在帮第一个女孩子查询之后，就记录下来这个色号已经没有了，下次其他女孩再来问这个色号的时候，直接告诉她没货了。</span></p>
  <p data-lake-id="u8bc62774" id="u8bc62774"><br></p>
  <p data-lake-id="u4dac1cee" id="u4dac1cee"><span data-lake-id="u39913463" id="u39913463">这样就可以避免每次都惊动总部了。</span></p>
  <p data-lake-id="u9b0e76a1" id="u9b0e76a1"><br></p>
  <p data-lake-id="u2cb8cbee" id="u2cb8cbee"><span data-lake-id="u1242e81b" id="u1242e81b">在缓存中，之所以会发生穿透，就是因为缓存没有对那些不存在的值得Key缓存下来，从而导致每次查询都要请求到数据库。</span></p>
  <p data-lake-id="ua8f1f8ad" id="ua8f1f8ad"><br></p>
  <p data-lake-id="u44c7b6cc" id="u44c7b6cc"><span data-lake-id="u05ccaa70" id="u05ccaa70">那么我们就</span><strong><span data-lake-id="u37c8e9ec" id="u37c8e9ec">可以为这些key对应的值设置为null并放到缓存中，这样再出现查询这个key 的请求的时候，直接返回null即可 。</span></strong></p>
  <p data-lake-id="u4f7b1c24" id="u4f7b1c24"><br></p>
  <p data-lake-id="ua25bfe0e" id="ua25bfe0e"><span data-lake-id="ub354834e" id="ub354834e">但是还需要注意的就是需要有一个失效时间，因为如果不设置失效的话，如果哪天总部有货了，门店还是当做没货的话，就会影响销量了。</span></p>
  <p data-lake-id="uaf8b64f2" id="uaf8b64f2"><br></p>
  <h3 data-lake-id="HVS6Y" id="HVS6Y"><span data-lake-id="u8f09512d" id="u8f09512d">BloomFilter</span></h3>
  <p data-lake-id="u523c5107" id="u523c5107"><br></p>
  <p data-lake-id="u8c60dac1" id="u8c60dac1"><span data-lake-id="u0ffef9f9" id="u0ffef9f9">很多时候，缓存穿透是因为有很多恶意流量的请求，这些请求可能随机生成很多Key来请求查询，这些肯定在缓存和数据库中都没有，那就很容易导致缓存穿透。</span></p>
  <p data-lake-id="uc1741927" id="uc1741927"><br></p>
  <p data-lake-id="uc6c3eeb1" id="uc6c3eeb1"><span data-lake-id="u3080358e" id="u3080358e">针对类似的情况，可以使用一个过滤器。</span></p>
  <p data-lake-id="ue9ca0764" id="ue9ca0764"><br></p>
  <p data-lake-id="ua1e9af0a" id="ua1e9af0a"><span data-lake-id="u2705b5b5" id="u2705b5b5">比如如果有一群人经常来门店问一些根本不存在的色号，比如五彩斑斓的黑，这些色号该品牌根本没生产过的话，店员就可以直接告诉顾客不存在就行了，也不需要惊动总部。</span></p>
  <p data-lake-id="u082a1d9b" id="u082a1d9b"><br></p>
  <p data-lake-id="u58c5517a" id="u58c5517a"><span data-lake-id="uc8938480" id="uc8938480">在缓存穿透防治上常用的技术是</span><strong><span data-lake-id="uf8b176e6" id="uf8b176e6">布隆过滤器(Bloom Filter)</span></strong><span data-lake-id="u2c612085" id="u2c612085">。</span></p>
  <p data-lake-id="u1dda79f6" id="u1dda79f6"><br></p>
  <p data-lake-id="uf0abcac5" id="uf0abcac5"><span data-lake-id="u198e62f3" id="u198e62f3">布隆过滤器是一种比较巧妙的概率性数据结构，它可以告诉你数据一定不存在或可能存在，相比Map、Set、List等传统数据结构它占用内存少、结构更高效。</span></p>
  <p data-lake-id="u7d08e3da" id="u7d08e3da"><br></p>
  <p data-lake-id="u2c46b0c9" id="u2c46b0c9"><span data-lake-id="ud1338ec9" id="ud1338ec9">对于缓存穿透，我们</span><strong><span data-lake-id="u43e4dbb6" id="u43e4dbb6">可以将查询的数据条件都哈希到一个足够大的布隆过滤器中，用户发送的请求会先被布隆过滤器拦截，一定不存在的数据就直接拦截返回了，从而避免下一步对数据库的压力。</span></strong></p>
  <p data-lake-id="ub16b0b76" id="ub16b0b76"><br></p>
  <h2 data-lake-id="i7EyT" id="i7EyT"><span data-lake-id="ud9ecbdd4" id="ud9ecbdd4">缓存击穿</span></h2>
  <p data-lake-id="u178d3420" id="u178d3420"><br></p>
  <p data-lake-id="u5aba082a" id="u5aba082a"><span data-lake-id="u7b712e6d" id="u7b712e6d">有一种比较特殊的情况，那就是如果某一个热门色号的口红刚好卖完了，这时候有很多顾客同时来咨询要购买这个色号，那么门店内的多个售货员可能分别给总部打电话咨询是否有存货。</span></p>
  <p data-lake-id="u6b023c44" id="u6b023c44"><br></p>
  <p data-lake-id="uec131401" id="uec131401"><span data-lake-id="u67dc6c77" id="u67dc6c77">或者如果有多家门店同时卖完了，那么总部接收到的咨询量就会剧增。类似这种情况，在缓存领域有一个类似的概念叫做</span><strong><span data-lake-id="ua00747e7" id="ua00747e7">缓存击穿</span></strong><span data-lake-id="u8598f9d0" id="u8598f9d0">。</span></p>
  <p data-lake-id="udf52a9b7" id="udf52a9b7"><br></p>
  <p data-lake-id="ue5dc50af" id="ue5dc50af"><img src="http://www.hollischuang.com/wp-content/uploads/2020/12/16089701925490.jpg?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_32%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"><span data-lake-id="ueaadef43" id="ueaadef43">​</span></p>
  <p data-lake-id="u11180bbf" id="u11180bbf"><br></p>
  <p data-lake-id="u0579d3c7" id="u0579d3c7"><span data-lake-id="ud5fe1b34" id="ud5fe1b34">缓存击穿是指当某一key的缓存过期时大并发量的请求同时访问此key，瞬间击穿缓存服务器直接访问数据库，让数据库处于负载的情况。</span></p>
  <p data-lake-id="ud5ea91c4" id="ud5ea91c4"><br></p>
  <h3 data-lake-id="vjatT" id="vjatT"><span data-lake-id="ubfe6d23f" id="ubfe6d23f">异步定时更新</span></h3>
  <p data-lake-id="ub2445200" id="ub2445200"><br></p>
  <p data-lake-id="udd50b423" id="udd50b423"><span data-lake-id="ubb0c07f4" id="ubb0c07f4">如果提前知道某一个色号比较畅销的话，那就可以定时的咨询总部是否还有存货，定时的更新库存情况就可以避免上面这种情况了。</span></p>
  <p data-lake-id="u3ae70969" id="u3ae70969"><br></p>
  <p data-lake-id="u6c38ae6a" id="u6c38ae6a"><span data-lake-id="u7b1e6287" id="u7b1e6287">在缓存处理上，同理，比如</span><strong><span data-lake-id="u32001989" id="u32001989">某一个热点数据的过期时间是1小时，那么每59分钟，通过定时任务去更新这个热点key，并重新设置其过期时间。</span></strong></p>
  <p data-lake-id="ue1e396e7" id="ue1e396e7"><br></p>
  <h3 data-lake-id="U376N" id="U376N"><span data-lake-id="ue1b1d1c5" id="ue1b1d1c5">互斥锁</span></h3>
  <p data-lake-id="ub68242d0" id="ub68242d0"><br></p>
  <p data-lake-id="u63731101" id="u63731101"><span data-lake-id="u5c491045" id="u5c491045">还有一种解决办法，那就是如果很多顾客咨询的是同一个色号的口红，那么就先处理第一个用户的咨询，其他同样请求的顾客先排队等待。一直到店员从总部那里获取到最新的库存信息后，就可以安排其他人继续购买了。</span></p>
  <p data-lake-id="ufe276236" id="ufe276236"><br></p>
  <p data-lake-id="u2dd59cc6" id="u2dd59cc6"><strong><span data-lake-id="u157543c4" id="u157543c4">在缓存处理上，通常使用一个互斥锁来解决缓存击穿的问题。简单来说就是当Redis中根据key获得的value值为空时，先锁上，然后从数据库加载，加载完毕，释放锁。若其他线程也在请求该key时，发现获取锁失败，则先阻塞。</span></strong></p>
  <p data-lake-id="ue0e278c6" id="ue0e278c6"><br></p>
  <h2 data-lake-id="RdL9V" id="RdL9V"><span data-lake-id="u68c3138c" id="u68c3138c">缓存雪崩</span></h2>
  <p data-lake-id="ua54991fe" id="ua54991fe"><br></p>
  <p data-lake-id="u92f32733" id="u92f32733"><span data-lake-id="u20c96b87" id="u20c96b87">如果门店内的多个色号的口红同时售罄了，并且门店在这个时间点刚好也不知道总部有没有库存了，这时候如果有大量顾客来到门店购物的话，就会有更多的咨询电话打到总部那里。</span></p>
  <p data-lake-id="ua5eebc86" id="ua5eebc86"><br></p>
  <p data-lake-id="ufaf65bb1" id="ufaf65bb1"><span data-lake-id="u623b8899" id="u623b8899">或者是门店突然出现问题了，不能提供服务了，很多顾客就可能自己打电话到总部咨询库存情况。类似这种情况，在缓存领域有一个类似的概念叫做</span><strong><span data-lake-id="u8fe567ee" id="u8fe567ee">缓存雪崩</span></strong><span data-lake-id="u504d6cf9" id="u504d6cf9">。</span></p>
  <p data-lake-id="ue98257ec" id="ue98257ec"><br></p>
  <p data-lake-id="u986ae5f4" id="u986ae5f4"><img src="http://www.hollischuang.com/wp-content/uploads/2020/12/16089705608027.jpg?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_32%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"><span data-lake-id="uf795dba8" id="uf795dba8">​</span></p>
  <p data-lake-id="u5aa9bf4f" id="u5aa9bf4f"><br></p>
  <p data-lake-id="u1ed65ab5" id="u1ed65ab5"><span data-lake-id="ueebf9b30" id="ueebf9b30">缓存雪崩是指当大量缓存同时过期或缓存服务宕机，所有请求的都直接访问数据库，造成数据库高负载，影响性能，甚至数据库宕机。</span></p>
  <p data-lake-id="u41bf2117" id="u41bf2117"><br></p>
  <h3 data-lake-id="lYJOf" id="lYJOf"><span data-lake-id="u54b73ea5" id="u54b73ea5">不同的过期时间</span></h3>
  <p data-lake-id="u2bf7276a" id="u2bf7276a"><br></p>
  <p data-lake-id="u8a9c2bbc" id="u8a9c2bbc"><span data-lake-id="u337172ad" id="u337172ad">为了避免缓存雪崩，门店可以考虑给不同的色号的口红预留不同的库存，并且采用不同的频率咨询总部库存情况，更新到门店中。这样就可以避免突然同一个时间点所有色号都售罄。</span></p>
  <p data-lake-id="u4b410800" id="u4b410800"><br></p>
  <p data-lake-id="u21d23390" id="u21d23390"><strong><span data-lake-id="u870f1d13" id="u870f1d13">为了避免大量的缓存在同一时间过期，可以把不同的key过期时间设置成不同的， 并且通过定时刷新的方式更新过期时间。</span></strong></p>
  <p data-lake-id="u56d4ba42" id="u56d4ba42"><br></p>
  <h3 data-lake-id="hYLnP" id="hYLnP"><span data-lake-id="u0290c500" id="u0290c500">集群</span></h3>
  <p data-lake-id="u37bed25d" id="u37bed25d"><br></p>
  <p data-lake-id="uf710faff" id="uf710faff"><span data-lake-id="ub506c36d" id="ub506c36d">为了避免门店出问题导致大量顾客直接打电话到总部，可以考虑开更多的门店，将用户分流到多个店铺中。</span></p>
  <p data-lake-id="u5cc8b155" id="u5cc8b155"><br></p>
  <p data-lake-id="u35c74195" id="u35c74195"><span data-lake-id="u43f462bf" id="u43f462bf">类似的，</span><strong><span data-lake-id="ua255c612" id="ua255c612">在缓存雪崩问题防治上面，一个比较典型的技术就是采用集群方式部署，使用集群可以避免服务单点故障。</span></strong></p>
 </body>
</html>